package com.admin.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;


import com.admin.common.enums.MemberLevelEnum;
import jakarta.annotation.PostConstruct;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.admin.common.constant.BizConstant;
import com.admin.common.enums.EnumResult;
import com.admin.common.shiro.ShiroUtils;
import com.admin.common.util.YsCollectionUtil;
import com.admin.domain.MenuDO;
import com.admin.mapper.AdminRoleMapper;
import com.admin.mapper.MenuMapper;
import com.admin.mapper.RoleMenuMapper;
import com.admin.service.MenuService;
import com.admin.service.TransactionService;
import com.admin.vo.PageVO;
import com.admin.vo.ResultVO;
import com.admin.vo.SimpleResultVO;
import com.admin.vo.system.ListMenuListVO;
import com.admin.vo.system.MenuSelectedVO;

@Service
public class MenuServiceImpl extends BaseServiceImpl<MenuDO> implements MenuService {

    @Autowired
    private TransactionService transactionService;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @PostConstruct
    private void init() {
        setBaseMapper(menuMapper);
    }

    @Override
    public SimpleResultVO deleteByPrimaryKeys(List<Long> menuIds) {
        SimpleResultVO result = new SimpleResultVO();
        if (CollectionUtils.isEmpty(menuIds)) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }

        Map<String, Object> params = YsCollectionUtil.createHashMap();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);

        List<Long> allChildIds = new ArrayList<Long>();
        for (Long menuId : menuIds) {
            getAllChildIds(menuId, allMenuDOs, allChildIds);
            allChildIds.add(menuId);
        }
        transactionService.deleteMenus(allChildIds);
        ShiroUtils.clearAllCachedAuthorization();

        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    @Override
    public SimpleResultVO deleteByPrimaryKey(Long menuId) {
        SimpleResultVO result = new SimpleResultVO();
        if (menuId == null) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }

        Map<String, Object> params = YsCollectionUtil.createHashMap();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);

        List<Long> allChildIds = new ArrayList<Long>();
        getAllChildIds(menuId, allMenuDOs, allChildIds);
        allChildIds.add(menuId);
        transactionService.deleteMenus(allChildIds);
        ShiroUtils.clearAllCachedAuthorization();

        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    /**
     * 递归查，当前菜单子菜单id
     * 
     * @param id 当前菜单id
     * @param allMenuDOs 要查找的列表
     * @param allChildIds 最终子菜单结果集
     */
    private void getAllChildIds(Long id, List<MenuDO> allMenuDOs, List<Long> allChildIds) {
        // 子菜单
        List<Long> childList = new ArrayList<Long>();
        for (MenuDO menu : allMenuDOs) {
            // 遍历所有节点，将父菜单id与传过来的id比较
            if (menu.getParentId().equals(id)) {
                childList.add(menu.getMenuId());
            }
        }

        // 加入最终结果集
        allChildIds.addAll(childList);

        // 把子菜单的子菜单再循环一遍
        for (Long menuId : childList) {
            // 递归
            getAllChildIds(menuId, allMenuDOs, allChildIds);
        } // 递归退出条件
        if (childList.size() == 0) {
            return;
        }
    }

    @Override
    public ResultVO<PageVO<ListMenuListVO>> getMenuVOs(Integer pageIndex, Integer pageSize,
        Map<String, Object> params) {
        ResultVO<PageVO<ListMenuListVO>> result = new ResultVO<PageVO<ListMenuListVO>>();
        if (params == null) {
            params = YsCollectionUtil.createHashMap();
        }
        PageVO<ListMenuListVO> page = new PageVO<ListMenuListVO>(pageIndex, pageSize);
        params.put("parentId", BizConstant.PARENT_ID_ZERO_LONG);
        Integer totalCount = menuMapper.countByMap(params);
        page.setTotalCount(totalCount);
        if (totalCount > 0) {
            params.put("startIndex", page.getStartIndex());
            params.put("pageSize", page.getPageSize());
            List<MenuDO> menuDOs = menuMapper.selectByMap(params);

            params.clear();
            List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);

            List<ListMenuListVO> menuListVOs = YsCollectionUtil.copyList(menuDOs, ListMenuListVO.class);
            for (ListMenuListVO menuListVO : menuListVOs) {
                menuListVO.setChildren(getChildVO(menuListVO.getMenuId(), allMenuDOs));
            }
            page.setData(menuListVOs);
        }
        result.setData(page);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    /**
     * 递归查，当前菜单子菜单
     * 
     * @param id 当前菜单id
     * @param allMenuDOs 要查找的列表
     * @return
     */
    private List<ListMenuListVO> getChildVO(Long id, List<MenuDO> allMenuDOs) {
        // 子菜单
        List<ListMenuListVO> childList = new ArrayList<ListMenuListVO>();
        for (MenuDO menu : allMenuDOs) {
            // 遍历所有节点，将父菜单id与传过来的id比较
            if (menu.getParentId().equals(id)) {
                ListMenuListVO menuListVO = new ListMenuListVO();
                BeanUtils.copyProperties(menu, menuListVO);
                childList.add(menuListVO);
            }
        }
        // 把子菜单的子菜单再循环一遍
        for (ListMenuListVO menu : childList) {// 没有url子菜单还有子菜单
            // 递归
            menu.setChildren(getChildVO(menu.getMenuId(), allMenuDOs));
        } // 递归退出条件
        if (childList.size() == 0) {
            return null;
        }
        return childList;
    }

    @Override
    public ResultVO<List<MenuSelectedVO>> getSelectMenus() {
        ResultVO<List<MenuSelectedVO>> result = new ResultVO<List<MenuSelectedVO>>();

        Map<String, Object> params = YsCollectionUtil.createHashMap();
        params.put("parentId", BizConstant.PARENT_ID_ZERO_LONG);
        List<MenuDO> menuDOs = menuMapper.selectByMap(params);

        params.clear();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);
        List<MenuSelectedVO> menuSelectedVOs = YsCollectionUtil.copyList(menuDOs, MenuSelectedVO.class);
        for (MenuSelectedVO menuSelectedVO : menuSelectedVOs) {
            menuSelectedVO.setIsSelected(false);
            menuSelectedVO.setChildren(getChildVO(null, menuSelectedVO.getMenuId(), allMenuDOs, ""));
        }

        result.setData(menuSelectedVOs);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    @Override
    public List<MenuSelectedVO> selectMenus(String level) {
        Map<String, Object> params = YsCollectionUtil.createHashMap();
        if (level.equals(MemberLevelEnum.PROVINCE.getKey())) {
            params.put("province", 1);
        } else if (level.equals(MemberLevelEnum.CITY.getKey())) {
            params.put("city", 1);
        } else if (level.equals(MemberLevelEnum.AREA.getKey())) {
            params.put("area", 1);
        }
        params.put("parentId", BizConstant.PARENT_ID_ZERO_LONG);
        List<MenuDO> menuDOs = menuMapper.selectByMap(params);

        params.clear();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);
        List<MenuSelectedVO> menuSelectedVOs = YsCollectionUtil.copyList(menuDOs, MenuSelectedVO.class);
        for (MenuSelectedVO menuSelectedVO : menuSelectedVOs) {
            menuSelectedVO.setIsSelected(false);
            menuSelectedVO.setChildren(getChildVO(null, menuSelectedVO.getMenuId(), allMenuDOs, level));
        }
        return menuSelectedVOs;
    }

    @Override
    public ResultVO<List<MenuSelectedVO>> getSelectMenus(Long roleId) {
        ResultVO<List<MenuSelectedVO>> result = new ResultVO<List<MenuSelectedVO>>();
        List<Long> menuIds = new ArrayList<Long>();
        if (roleId != null) {
            menuIds = roleMenuMapper.selectMenuIdByRoleId(roleId);
        }

        Map<String, Object> params = YsCollectionUtil.createHashMap();
        params.put("parentId", BizConstant.PARENT_ID_ZERO_LONG);
        List<MenuDO> menuDOs = menuMapper.selectByMap(params);

        params.clear();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);
        // 封装页面需要的VO
        List<MenuSelectedVO> menuSelectedVOs = YsCollectionUtil.copyList(menuDOs, MenuSelectedVO.class);
        for (MenuSelectedVO menuSelectedVO : menuSelectedVOs) {
            if (menuIds.contains(menuSelectedVO.getMenuId())) {
                menuSelectedVO.setIsSelected(true);
            } else {
                menuSelectedVO.setIsSelected(false);
            }
            menuSelectedVO.setChildren(getChildVO(menuIds, menuSelectedVO.getMenuId(), allMenuDOs, ""));
        }
        result.setData(menuSelectedVOs);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    /**
     * 递归查，当前菜单子菜单
     * 
     * @param menuIdsSelected 选中菜单id
     * @param id 当前菜单id
     * @param allMenuDOs 要查找的列表
     * @return
     */
    private List<MenuSelectedVO> getChildVO(List<Long> menuIdsSelected, Long id, List<MenuDO> allMenuDOs, String type) {
        // 子菜单
        List<MenuSelectedVO> childList = new ArrayList<>();
        for (MenuDO menu : allMenuDOs) {
            // 遍历所有节点，将父菜单id与传过来的id比较
            if (menu.getParentId().equals(id)) {
                MenuSelectedVO menuListVO = new MenuSelectedVO();
                BeanUtils.copyProperties(menu, menuListVO);
                if (CollectionUtils.isNotEmpty(menuIdsSelected) && menuIdsSelected.contains(menu.getMenuId())) {
                    menuListVO.setIsSelected(true);
                } else {
                    menuListVO.setIsSelected(false);
                }

                if (type.equals(MemberLevelEnum.PROVINCE.getKey())) {
                    if (menu.getProvince() == 1) {
                        childList.add(menuListVO);
                    }
                } else if (type.equals(MemberLevelEnum.CITY.getKey())) {
                    if (menu.getCity() == 1) {
                        childList.add(menuListVO);
                    }
                } else if (type.equals(MemberLevelEnum.AREA.getKey())) {
                    if (menu.getArea() == 1) {
                        childList.add(menuListVO);
                    }
                } else {
                    childList.add(menuListVO);
                }
            }
        }
        // 把子菜单的子菜单再循环一遍
        for (MenuSelectedVO menu : childList) {// 没有url子菜单还有子菜单
            // 递归
            menu.setChildren(getChildVO(menuIdsSelected, menu.getMenuId(), allMenuDOs, type));
        } // 递归退出条件
        if (childList.size() == 0) {
            return null;
        }
        return childList;
    }

    @Override
    public SimpleResultVO saveMenuDO(MenuDO menuDO) {
        SimpleResultVO result = new SimpleResultVO();
        if (menuDO == null || menuDO.getParentId() == null || StringUtils.isEmpty(menuDO.getName())
            || StringUtils.isEmpty(menuDO.getPerms())) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }

        insertSelective(menuDO);

        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    @Override
    public SimpleResultVO updateMenuDO(MenuDO menuDO) {
        SimpleResultVO result = new SimpleResultVO();
        if (menuDO == null || menuDO.getMenuId() == null) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }
        updateSelective(menuDO);

        ShiroUtils.clearAllCachedAuthorization();

        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    @Override
    public ResultVO<List<String>> getCanSeeMenuPerms(Integer userId) {
        ResultVO<List<String>> result = new ResultVO<List<String>>();
        if (userId == null) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }
        List<String> perms = new ArrayList<String>();
        List<Long> roleIds = adminRoleMapper.getRoleIdsByUserId(userId);
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<Long> menuIds = roleMenuMapper.selectMenuIdByRoleIds(roleIds);
            Map<String, Object> params = YsCollectionUtil.createHashMap();
            params.put("menuIds", menuIds);
            List<MenuDO> menuDOs = menuMapper.selectByMap(params);
            for (MenuDO menuDO : menuDOs) {
                perms.add(menuDO.getPerms());
            }
        }
        result.setData(perms);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }

    @Override
    public ResultVO<Set<Long>> getParentIds(List<Long> menuIds) {
        ResultVO<Set<Long>> result = new ResultVO<Set<Long>>();
        if (CollectionUtils.isEmpty(menuIds)) {
            result.setCode(EnumResult.PARAM_NULL.getCode());
            result.setMsg(EnumResult.PARAM_NULL.getMsg());
            return result;
        }

        Map<String, Object> params = YsCollectionUtil.createHashMap();
        params.put("menuIds", menuIds);
        List<MenuDO> menuDOs = menuMapper.selectByMap(params);
        if (CollectionUtils.isEmpty(menuDOs)) {
            result.setCode(EnumResult.DATA_NULL.getCode());
            result.setMsg(EnumResult.DATA_NULL.getMsg());
            return result;
        }

        params.clear();

        Set<Long> parentIds = new HashSet<Long>();
        List<MenuDO> allMenuDOs = menuMapper.selectByMap(params);
        for (MenuDO menuDO : menuDOs) {
            getParentIds(menuDO.getParentId(), allMenuDOs, parentIds);
        }

        result.setData(parentIds);
        result.setCode(EnumResult.SUCCESS.getCode());
        result.setMsg(EnumResult.SUCCESS.getMsg());
        return result;
    }



    /**
     * 递归遍历父id
     * 
     * @param parentId 当前菜单的父id
     * @param allMenuDOs 所有菜单
     * @param parentIds 所有父菜单结果集
     */
    private void getParentIds(Long parentId, List<MenuDO> allMenuDOs, Set<Long> parentIds) {
        if (parentId == null || parentId.equals(BizConstant.PARENT_ID_ZERO_LONG)) {
            return;
        }
        for (MenuDO menuDO : allMenuDOs) {
            if (menuDO.getMenuId().equals(parentId)) {
                getParentIds(menuDO.getParentId(), allMenuDOs, parentIds);
            }
        }
        parentIds.add(parentId);
    }

    @Override
    public List<String> getPermissionsModule(Integer userId) {
        List<String> perms = new ArrayList<>();
        List<Long> roleIds = adminRoleMapper.getRoleIdsByUserId(userId);
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<Long> menuIds = roleMenuMapper.selectMenuIdByRoleIds(roleIds);
            Map<String, Object> params = YsCollectionUtil.createHashMap();
            params.put("menuIds", menuIds);
            List<MenuDO> menuDOs = menuMapper.selectByMap(params);
            for (MenuDO menuDO : menuDOs) {
                if (menuDO.getPerms().equals("provinceScore:M10000") ||
                        menuDO.getPerms().equals("provinceScore:M20000") ||
                        menuDO.getPerms().equals("provinceScore:M30000") ||
                        menuDO.getPerms().equals("provinceScore:M40000") ||
                        menuDO.getPerms().equals("provinceScore:M50000") ||
                        menuDO.getPerms().equals("provinceScore:M60000") ||
                        menuDO.getPerms().equals("provinceScore:M70000")
                ) {
                    perms.add(menuDO.getName());
                }
            }
        }
        return perms;
    }
}
